﻿/**
 * @fileOverview This file contains definition of classes intended to animate widgets.
 * @author GUI group 
 * @version 0.9 beta
 */
 
/**
* @ignore
*/
function elaborate(id) {

    var width = parseInt($("#" + id).css("width"));
    var height = parseInt($("#" + id).css("height"));

    var obj = $("#" + id).offset();
    var vert_a_x = obj.left;
    var vert_a_y = obj.top;
    var vert_b_x = vert_a_x + width;
    var vert_c_y = vert_a_y + height;

    return {
        a: { x: vert_a_x, y: vert_a_y },
        b: { x: vert_b_x, y: vert_a_y },
        c: { x: vert_b_x, y: vert_c_y },
        d: { x: vert_a_x, y: vert_c_y },
        base: width,
        altezza: height,
        area: width * height
    }
}

/**
* @ignore
*/
function isContainer(id, id_c) {

    var ret_1 = elaborate(id);
    var ret_2 = elaborate(id_c);

    if (area && container) {
        var container = elaborate(area);
        var left = container.a.x;
        var right = container.b.x;
        var top = container.a.y;
        var bottom = container.c.y;
    }

    var base = Math.min(ret_1.c.x, ret_2.c.x)- Math.max(ret_1.d.x, ret_2.d.x);
	if(base <= 0)
	    return 0;
	
	var altezza = Math.min(ret_1.d.y,ret_2.d.y) - Math.max(ret_1.a.y,ret_2.a.y);
	if(altezza <=0)
	    return 0;
	
	var area =base * altezza;
	var totArea = ret_1.area;

    var percent = 100 * (area / totArea); //percentuale di copertura
    return percent;
}

/**
* @ignore
*/
function test(that, id, list_container) {
    var flag = false;
    var iter = IteratorArray(list_container.id);
    while (iter.hasNext() && flag == false) {
        var item = iter.next();
        p = isContainer(id, item.value.toString());
        //alert(p + "/" + item + ' ' + item.value + ' id' + id);
        if (p > list_container.perc) {
            flag = true;
            that.result = item.value;
            return true;
        }
    }
    return false;
};
/**/
/**
* @class Widget through the object can be animated.
* @constructor
* @param {object} obj The object that has to be animated. 
*/
function Animation(obj) {
    
    /** The object that has to be animated.
    *   @field 
    *   @type object
    */
    this.obj = obj;
    /** A map of CSS properties that the animation will move toward.
    *   @field 
    *   @type object
    *   @default empty
    */
    this.css = {};
    /** An object that contains Duration, Queue, Easing, Step and Complete of the animation. 
    *   @field 
    *   @type object
    *   @default empty
    */	
    this.param = {};
    
    /** An object that contains Percentage and Container's identificator.
    *   @field 
    *   @type object
    *   @default empty
    */    
    this.list_container = {};
    /** An object that contains Value and External Border identificator's.
    *   @field 
    *   @type object
    *   @default empty
    */
    this.list_border_out = {};
    /** An object that contains Value and Internal Border identificator's.
    *   @field 
    *   @type object
    *   @default empty
    */
    this.list_border_in= {};
  
    /** The container's identificator where is the animate object.
    *   @field 
    *   @type string
    *   @default null
    */
    this.result = null;

    /** The percentage of overlap.
    *   @field 
    *   @type number
    *   @default 100
    */    
    this.perc = 100;
}

/** 
* Set a map of CSS properties that the animation will move toward.
* @param {object} [css]
* @returns 0 if css is an object, -1 otherwise
* @example &#123;top: "325", left: "-=5"&#125;
*/
Animation.prototype.setCss = function(css) {
    if (typeof css == "object") {
        this.css = css;
        return 0;
    }
    else return -1;
}

/**
* Set a function to call once the animation is complete. 
* @param {function} [complete]
* @returns 0 if complete is a function, -1 otherwise
* @example MyAnim.complete(function(){ alert("Hello World!");})
*/
Animation.prototype.setComplete = function(complete) {
    if (typeof complete == "function"){
        this.param.complete = complete;
        return 0;
    }
    else return -1;
}

/**
* Set a function to be called after each step of the animation. 
* @param {function} [step]
* @returns 0 if step is a function, -1 otherwise
* @example MyAnim.step(function(){ alert("Hello World!");})
*/
Animation.prototype.setStep = function(step) {
    if (typeof step == "function")
    {
        this.param.step = step;
        return 0;
    }
    else return -1;
}

/**
* Set a string or number determining how long the animation will run.
* @param {string|number} [duration = fast]  The strings 'fast' and 'slow' can be supplied to indicate durations of 200 and 600 milliseconds, respectively.
* @returns 0 if duration is a number or it's a string with value slow or fast, -1 otherwise
*/
Animation.prototype.setDuration = function(duration) {
    if (typeof duration == "number" || duration == "slow" || duration == "fast")
        this.param.duration = duration;
}

/**
* A string indicating which easing function to use for the transition.
* @param {string} [easing = swing] If 'linear' the animation progresses at constant pace. 
* @returns 0 if easing is a string with value swing or linear, -1 otherwise
*/
Animation.prototype.setEasing = function(easing) {
    if ((typeof easing == "string") && (easing == "swing" || easing == "linear"))
    {
        this.param.easing = easing;
        return 0;
    }
    else return -1;
}

/**
* Set Boolean indicating whether to place the animation in the effects queue. 
* @param {boolean} [queue = true] If false, all the animation assing to the object will begin immediately at the same time. 
* @returns 0 if queue is a boolean, -1 otherwise  
*/
Animation.prototype.setQueue = function(queue) {
    if (typeof queue == "boolean")
    {
        this.param.queue = queue;
        return 0;
    }
    else return -1;
}

/**
* Set the lowest percentage of overlap (pixel) to decide if the animated object is contained in almost in almost one of containers.
* @param {number} [perc = 100]
* @returns 0 if perc is a number, -1 otherwise 
* @example MyAnim.setContainerPercentage(25,001);
*/
Animation.prototype.setContainerPercentage = function(perc) {
    if (typeof perc == "number") {
        this.list_container.perc = perc;
        return 0;
    }
    else return -1;
}

/**
* Set the list of objects used as containers.
* @param {object} [list] The container's identificators.
* @returns 0 if list is an object, -1 otherwise
* @example MyAnim.setContainerList({"div_1", "div_2", "div_3"});
*/
Animation.prototype.setContainerList = function(list) {
    if (typeof list == "object") {
        var listid = Array();
        var iter = IteratorArray(list);
        while (iter.hasNext()) {
            var item = iter.next();
            listid.push(item.value.id);
        }
        this.list_container.id = listid;
        return 0;
    }
    else return -1;
}

/**
* This value must to be true if the animated object must bounce on external borders. 
* @param {boolean} [value] 
* @returns 0 if value is a boolean, -1 otherwise
*/
Animation.prototype.setBorderOutValue = function(value){
    if(typeof value == "boolean"){
        this.list_border_out.value = value;
    }
    else return -1;
}

/**
* Set the list of objects where the animated object must bounce on external borders.
* @param {object} [list_border_out] The external border's identificators.
* @returns 0 if list_border_out is an object, -1 otherwise
* @example MyAnim.setListBorderOut({"div_1", "div_2", "div_3"});
*/
Animation.prototype.setListBorderOut = function(list_border_out) {
    if (typeof list_border_out == "object") {
        this.list_border_out.id = list_border_out;
        return 0;
    }
    else return -1;
}

/**
* This value must to be true if the animated object must bounce on internal borders. 
* @param {boolean} [value] 
* @returns 0 if value is a boolean, -1 otherwise
*/
Animation.prototype.setBorderInValue = function(value){
    if(typeof value == "boolean"){
        this.list_border_in.value = value;
    }
    else return -1;
}
/**
* Set the list of object where the animated object must bounce on internal borders.
* @param {object} [list_border_in] The internal border's idenficators.
* @returns 0 if list_border_in is an object, -1 otherwise
* @example MyAnim.setListBorderIn({"div_1", "div_2", "div_3"});
*/
Animation.prototype.setListBorderIn = function(list_border_in) {
    if (typeof list_border_in == "object") {
        this.list_border_in.id = list_border_in;
        return 0;
    }
    else return -1;
}

/**
*   Widget used to implement the animation of the object with all the parameter that user define.
*   @param {Boolean} [pick = false] It's true if you want use the function to control when the animate object is overlap with almost one of container.
*   @param {Boolean} [pick_s = false] It's true if you want stop the animation when there is the overlap.
*/
Animation.prototype.animate_w = function(pick, pick_s) {
	/** @ignore */
    this.p = 0;
	/** @ignore */
    this.pick = 0;
	/** @ignore */
    this.param_r = {};
	/** @ignore */
    this.css_r = {};
    var p = this.p;
    var id = this.obj.id;
    var list_container = this.list_container;
    var list_border_in = this.list_border_in;
    var list_border_out = this.list_border_out;
    var css = this;
    var that = this;
    var complete = false;
	
    if (this.param) {
        if (pick) {
            if (this.param.complete != null) {
                complete = this.param.complete;

                if (pick_s) {
					/** @ignore */
                    this.param_r.complete = function() {
						
                        complete();
                    };
                }
                else {
					/** @ignore */
                    this.param_r.complete = function() {
                        test(that, id, list_container);
                        complete();
                    };
                }
            }
            else {
                if (!pick_s) {
					/** @ignore */
                    this.param_r.complete = function() {
                        test(that, id, list_container);
                    };
                }
            }
            if (this.param.step != null) {
                var step = this.param.step;
                if (pick_s) {
					/** @ignore */
                    this.param_r.step = function() {
                        if (step() || test(id, list_container)) {
                            test(that, id, list_container);
                            $("#" + id).stop();
                            if (complete) complete();
                        }
                    };
                }
                else {
					/** @ignore */
                    this.param_r.step = function() {
                        if (step()) {
                            $("#" + id).stop();
                            test(that, id, list_container);
                            if (complete) complete();
                        }
                    };
                }
            }
            else {
                if (pick_s) {
					/** @ignore */
                    this.param_r.step = function() {
                            test(that, id, list_container);
                            $("#" + id).stop();
                            if (complete) complete();
                    };
                }
            }
        }
        else {
            if (this.param.complete != null) {
                complete = this.param.complete;
				/** @ignore */
                this.param_r.complete = function() {
                    complete();
                }
            }
        }
    }
    /** @ignore */
    this.param_r.queue = this.param.queue;
	/** @ignore */
    this.param_r.easing = this.param.easing;
	/** @ignore */
    this.param_r.duration = this.param.duration;
	/** @ignore */
    $("#" + id).animate(this.css, this.param_r);

    return 0;
};
